//
// Created by Zsir on 2025/7/29.
//

#include <netdb.h>
#include <fcntl.h>
#include <cstring>
#include <malloc.h>
#include <iostream>
#include "arpa/inet.h"
#include "sys/socket.h"
#include "HTTP.h"

void HTTP::hostToIp()
{
    if (hostname_ == nullptr)
    {
        std::cout << "hostname = nullptr" << std::endl;
        return;
    }
    
    // 检查是否是IP地址格式
    struct in_addr addr;
    if (inet_aton(hostname_, &addr) != 0)
    {
        // 是IP地址，直接使用
        ip_ = (char*)hostname_;
        std::cout << "Using IP address: " << ip_ << std::endl;
    }
    else
    {
        // 是域名，需要解析
        host_ = gethostbyname(hostname_);
        if (host_)
        {
            ip_ = inet_ntoa(*(struct in_addr *) host_->h_addr_list[0]);
            std::cout << "Resolved " << hostname_ << " to " << ip_ << std::endl;
        } else
        {
            std::cout << "Failed to resolve hostname: " << hostname_ << std::endl;
        }
    }
}

int HTTP::connect()
{
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    struct sockaddr_in sin = {0};

    sin.sin_family = AF_INET;
    sin.sin_port = htons(port_);
    sin.sin_addr.s_addr = inet_addr(ip_);

    if (::connect(sockfd, (struct sockaddr *) &sin, sizeof(struct sockaddr_in)) != 0)
    {
        return -1;
    }
    fcntl(sockfd, F_SETFL, O_NONBLOCK);
    sockfd_ = sockfd;
    return sockfd;
}

char *HTTP::sendRequest(const char *resource)
{
    char buffer[BUFFER_SIZE] = {0};
    sprintf(buffer,
            "GET %s %s\r\n"
            "Host: %s\r\n"
            "%s"
            "\r\n", resource, HTTP_VERSION, hostname_, CONNECTION_TYPE);

    send(sockfd_, buffer, strlen(buffer), 0);

    char *result = (char *) malloc(1);
    result[0] = '\0';
    size_t total_len = 0;

    while (1)
    {
        fd_set fds;
        FD_ZERO(&fds);
        FD_SET(sockfd_, &fds);

        struct timeval tv{};
        tv.tv_sec = 5;
        tv.tv_usec = 0;

        int selection = select(sockfd_ + 1, &fds, nullptr, nullptr, &tv);
        if (selection <= 0)
        {
            break;
        }

        if (!FD_ISSET(sockfd_, &fds))
        {
            break;
        }

        memset(buffer, 0, BUFFER_SIZE);
        ssize_t len = recv(sockfd_, buffer, BUFFER_SIZE, 0);
        if (len <= 0)
        {
            break;
        }

        void *new_result = realloc(result, total_len + len + 1);
        if (!new_result)
        {
            free(result);
            return nullptr;
        }
        result = (char *) new_result;
        memcpy(result + total_len, buffer, len);
        total_len += len;
        result[total_len] = '\0';
    }

    if (total_len == 0)
    {
        free(result);
        return nullptr;
    }

    return result;
}

HTTP::HTTP(const char *hostname, int port)
    :
    hostname_(hostname), port_(port)
{
    hostToIp();
}
